﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Common;




namespace XnaSuperGame
{

   /// <summary>
   /// This is the main type for your game 
   /// </summary>
   public class XNAGame : Microsoft.Xna.Framework.Game
   {

      #region ClassMembers

      public Background background;
      public GraphicsDeviceManager Graphics;
      public SpriteBatch spriteBatch;
		public MouseClipper mouseClipper;
		
		public ContentHelper ContentHelper;
    
      //font for version text
      public SpriteFont FontVerText;
      //Sprite for mouse cursor
      public Texture2D cursorTex;

		//Local Manager for invoke manager methods from inherited clases without using Constructor 
		protected ContentManager ContentManager;

      public GObject player;
      public int playerHP;
      //  GObject enemy;

      /// <summary>
      /// array for maximum cannonballs number
      /// </summary>
      public GObject[] cannonballs;
      const int maxcannonballs = 5;

      /// <summary>
      /// enemies randomizer
      /// as constants
      /// </summary>
      public GObject[] enemies;
      public Random VBR = new Random();

      const int maxEnemies = 3;
      const float maxEnemiesHeight = 0.1f;
      const float minEnemiesHeight = 0.5f;
      const float maxEnemiesVelocity = 5.0f;
      const float minEnemiesVelocity = 1.0f;

      //anur 
      //player speed, 100 pixels a second if we multiply it by milliseconds passed from last update
      const float playerSpeed = 0.2F;
      /// <summary>
      /// fess
      /// description of mouse state
      /// </summary>
      public MouseState prevMouse = Mouse.GetState();
		      

      GameStates CurrentGameState = GameStates.Menu;
      GameButton StartButton;
		StartMenu StartMenu;
   
      
      
      #endregion

      /// <summary>
      /// enemies randomizer
      /// as constants
      /// </summary>
      public XNAGame()
      {
         //resize window
         Graphics = new GraphicsDeviceManager(this);
			background = new Background();
         Graphics.PreferredBackBufferHeight = 768;
         Graphics.PreferredBackBufferWidth = 1024;
         Content.RootDirectory = "Content";
         mouseClipper = new MouseClipper();
         playerHP = 100;
			ContentManager = Content;
			ContentHelper = new ContentHelper(Content);
        }

      /// <summary>
      /// Allows the game to perform any initialization it needs to before starting to run.
      /// This is where it can query for any required services and load any non-graphic
      /// related content.  Calling base.Initialize will enumerate through any components
      /// and initialize them as well.
      /// </summary>
      protected override void Initialize()
      {
         // TODO: Add your initialization logic here
         base.Initialize();
   
         this.Window.AllowUserResizing = true;
         this.Window.Title = "Flesstohanurmius";
			this.IsMouseVisible = false;

      }

      protected string GetVersion()
      {
         string version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
         return version;
      }


      /// <summary>
      /// UnloadContent will be called once per game and is the place to unload
      /// all content.
      /// </summary>
      protected override void UnloadContent()
      {
         // TODO: Unload any non ContentManager content here
         mouseClipper.UnClipCursor();
      }

      /// <summary>
      /// Updates player state
      /// </summary>
      /// <param name="keyboard">KeyboardState</param>
      /// <param name="gameTime">GameTime</param>
      protected void UpdatePlayer(KeyboardState keyboard, MouseState mouse, GameTime gameTime)
      {
         //player Movement. Multiply time passed from last update by player speed
         if (keyboard.IsKeyDown(Keys.W))
         {
            player.position.Y -= (float)gameTime.ElapsedGameTime.TotalMilliseconds * playerSpeed;
         }
         if (keyboard.IsKeyDown(Keys.S))
         {
            player.position.Y += (float)gameTime.ElapsedGameTime.TotalMilliseconds * playerSpeed;
         }
         if (keyboard.IsKeyDown(Keys.D))
         {
            player.position.X += (float)gameTime.ElapsedGameTime.TotalMilliseconds * playerSpeed;
         }
         if (keyboard.IsKeyDown(Keys.A))
         {
            player.position.X -= (float)gameTime.ElapsedGameTime.TotalMilliseconds * playerSpeed;
         }

         //Player rotation.
         //subtract player coords to get vector from player to mouse
         Vector2 direction;
         direction.X = mouse.X - player.position.X;
         direction.Y = mouse.Y - player.position.Y;
         //get angle
         float rot = (float)Math.Atan2(direction.Y, direction.X);
         //rotate
         player.rotation = rot;

      }


      /// <summary>
      /// kill out-of-screen cannonballs and update cannonball position
      /// </summary>
      protected void UpdateCannonballs()
      {
         foreach (var cb in cannonballs)
         {
            
            if (cb.alive && (cb.position.Y > Graphics.GraphicsDevice.Viewport.Height
                           || cb.position.Y < 0
                           || cb.position.X > Graphics.GraphicsDevice.Viewport.Width
                           || cb.position.X < 0))
            {
               cb.alive = false;
            }
            
            if (cb.alive)
            {
               cb.position += cb.velocity;
            }
         }
      }


      /// <summary>
      /// fess cannonballs & enemies collision description 
      /// </summary>
      protected void ProcessCombat()
      {
            
            foreach (var en in enemies)
            {
               foreach(var cb in cannonballs)
               if (cb.alive && en.alive)
               {
                  if ( en.HitBox().Intersects(cb.HitBox()) )
                  {
                     en.alive = false;
                     cb.alive = false;
                  }
               }

            }
      }


      /// <summary>
      /// fess
      /// enemies movement
      /// </summary>
      public void UpdateEnemies()
      {
         foreach (GObject enemy in enemies)
         {
            if (enemy.alive)
            {
               enemy.position += enemy.velocity;
               if (
                       enemy.position.Y > Graphics.GraphicsDevice.Viewport.Height
                   || enemy.position.Y < 0
                   || enemy.position.X > Graphics.GraphicsDevice.Viewport.Width
                   || enemy.position.X < 0
                )
               {
                  enemy.alive = false;
                  playerHP--; 
               }

               Vector2 direction;
               direction.X = (player.position.X - enemy.position.X);
               direction.Y = (player.position.Y - enemy.position.Y);
               //get angle
               float rot = (float)Math.Atan2(direction.Y, direction.X);
               //rotate
               enemy.rotation = rot;

            }
            else
            {
               enemy.alive = true;

               enemy.position = new Vector2(Graphics.GraphicsDevice.Viewport.Width,

                //   );
                    MathHelper.Lerp(
             (float)Graphics.GraphicsDevice.Viewport.Width * minEnemiesHeight,
                    (float)Graphics.GraphicsDevice.Viewport.Width * maxEnemiesHeight,
                   (float)VBR.NextDouble()));

               enemy.velocity = new Vector2(


                    MathHelper.Lerp(
                         -minEnemiesVelocity,
                         -maxEnemiesVelocity,
                         (float)VBR.NextDouble()), 0);


            }
         }
      }



      /// <summary>
      /// LoadContent will be called once per game and is the place to load
      /// all of your content.
      /// </summary>
      protected override void LoadContent()
      {
         // Create a new SpriteBatch, which can be used to draw textures.
         spriteBatch = new SpriteBatch(GraphicsDevice);
						
//			Texture2D bgtx = Content.Load<Texture2D>("sprite\\background");
			background.LoadContent(ContentHelper.GetTexture("background", ContentTypes.Background), ContentHelper.GetTexture("background", ContentTypes.Background));



         player = new GObject(ContentHelper.GetTexture("cannon",ContentTypes.Sprite));
         player.position = new Vector2(120, Graphics.GraphicsDevice.Viewport.Height - 240);

         /// fess
         /// cannonballs description and limiter
         /// 
         cannonballs = new GObject[maxcannonballs];
         for (int i = 0; i < maxcannonballs; i++)
         {
				cannonballs[i] = new GObject(ContentHelper.GetTexture("cannonball", ContentTypes.Sprite));
         }

         enemies = new GObject[maxEnemies];
         for (int i = 0; i < maxEnemies; i++)
         {
				enemies[i] = new GObject(ContentHelper.GetTexture("enemy", ContentTypes.Sprite));
         }

         //font for version text
         FontVerText = Content.Load<SpriteFont>("SpriteFontVersion");

         //Cursor sprite
			cursorTex = ContentHelper.GetTexture("cursor", ContentTypes.Sprite);
         // TODO: use this.Content to load your game content here


         //MenuButtons
			//StartButton = new MenuButton(GraphicsDevice, ContentHelper.GetTexture("start-icon", ContentTypes.Sprite));
			StartMenu = new StartMenu(this);
       
      }



      /// <summary>
      /// Allows the game to run logic such as updating the world,
      /// checking for collisions, gathering input, and playing audio.
      /// </summary>
      /// <param name="gameTime">Provides a snapshot of timing values.</param>
      /// 
      protected override void Update(GameTime gameTime)
      {





         KeyboardState keyboard = Keyboard.GetState();
         MouseState mouse = Mouse.GetState();

         switch (CurrentGameState) 
         {
            
            case GameStates.Menu:
               #region UpdateMenu

					StartMenu.Update(mouse);
			      if (StartMenu.GetState() != GameStates.Menu) CurrentGameState = StartMenu.GetState();

               #endregion
               break;
            case GameStates.Game:
               #region UpdateGame

               /// fess
               /// cannonballs positions & mouse click
               /// added "click moment" tracking
               /// 
               if ((prevMouse.LeftButton == ButtonState.Released) && (mouse.LeftButton == ButtonState.Pressed))
               {
                  foreach (var x in cannonballs)
                  {
                     if (!x.alive)
                     {
                        x.alive = true;
                        x.position = player.position;
                        x.velocity = 15.0f * new Vector2((float)Math.Cos(player.rotation), (float)Math.Sin(player.rotation));
                        break;
                     }
                  }

               }

               //Update mouse clipping
               bool newMouseVisible = false;
               mouseClipper.UpdateClipping(this.Window, this.IsActive, keyboard, ref newMouseVisible);
               IsMouseVisible = newMouseVisible;

               background.Update(gameTime);

               
               UpdatePlayer(keyboard, mouse, gameTime);
               UpdateCannonballs();
               UpdateEnemies();
               ProcessCombat();

               prevMouse = mouse;

               #endregion
               break;
            case GameStates.Options:
               break;
         }

            
         // Allows the game to exit
         if (keyboard.IsKeyDown(Keys.Q))
         {
            this.Exit();
         }

         base.Update(gameTime);

      }


      /// <summary>
      /// This is called when the game should draw itself.
      /// </summary>
      /// <param name="gameTime">Provides a snapshot of timing values.</param>
      protected override void Draw(GameTime gameTime)
      {
         MouseState ms = Mouse.GetState();
         var kb = Keyboard.GetState();
         
         GraphicsDevice.Clear(Color.CornflowerBlue);
         spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);

         switch (CurrentGameState)
         {
            case GameStates.Menu:
               #region MenuDraw
					spriteBatch.Draw(ContentHelper.GetTexture("MenuBackground", ContentTypes.Background), GraphicsDevice.ScissorRectangle, Color.White);

					StartMenu.Draw(spriteBatch);
               //StartButton.Draw(spriteBatch);

               //anur
               //draw mouse cursor 
               //TODO (too slow)
               if (IsActive)
               {
                  Vector2 mpos;
                  mpos.X = ms.X - cursorTex.Bounds.Width / 2;
                  mpos.Y = ms.Y - cursorTex.Bounds.Height / 2;
                  spriteBatch.Draw(cursorTex, mpos, Color.White);
               }
               
               
               #endregion
               break;

            case GameStates.Game:
               #region GameDraw
               
               //draw background
               background.Draw(spriteBatch, Window);

               //anur
               //draw mouse cursor 
               //TODO (too slow)
               if (IsActive)
               {
                  Vector2 mpos;
                  mpos.X = ms.X - cursorTex.Bounds.Width / 2;
                  mpos.Y = ms.Y - cursorTex.Bounds.Height / 2;
                  spriteBatch.Draw(cursorTex, mpos, Color.White);
               }
               
               //draw cannon
               spriteBatch.Draw(player.sprite,
                    player.position, null, Color.White,
                    player.rotation,
                    player.center, 1.0f,
                    SpriteEffects.None, 0);

               // fess 
               // cannonballs drawing
               foreach (GObject ball in cannonballs)
               {
                  if (ball.alive)
                  {
                     spriteBatch.Draw(ball.sprite, ball.position, Color.Yellow);
                  }
               }

               // fess
               // enemies drawing
               foreach (GObject enemy in enemies)
               {
                  if (enemy.alive)
                  {
                     spriteBatch.Draw(enemy.sprite,
                    enemy.position, null, Color.White,
                    enemy.rotation,
                    enemy.center, 1.0f,
                    SpriteEffects.None, 0);

                     //enemy.sprite, enemy.position, Color.White);
                  }
               }

               //anur
               //show version
               if (kb.IsKeyDown(Keys.V))
               {
                  Vector2 pos = new Vector2(0, 0);
                  spriteBatch.DrawString(FontVerText, GetVersion(), pos, Color.Blue);
               }
               Vector2 posHP = new Vector2((Window.ClientBounds.Width / 2 - 50), (Window.ClientBounds.Height - 50));
               spriteBatch.DrawString(FontVerText, playerHP.ToString(), posHP, Color.Blue);
               #endregion
               break;

            case GameStates.Options:
               #region OptionsDraw
               #endregion
               break;
               
         }

         spriteBatch.End();
   

         // TODO: Add your drawing code here

         base.Draw(gameTime);
      }
   }
}
